use std::{rc::Rc, cell::RefCell};

use crate::{instructions::base::Instruction, rtda::{Frame, heap::{Constant, string_pool}}};

// ldc和ldc_w指令用于加载int、float和字符串常量，ldc和ldc_w指令的区别仅在于操作数的宽度。
#[derive(Debug, Default)]
pub struct LDC {
    index: usize
}

impl Instruction for LDC {
    fn fetch_operands(&mut self, reader: &mut crate::instructions::base::BytecodeReader) {
        self.index = reader.read_u8() as usize;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        _ldc(frame, self.index)
    }
}

#[derive(Debug, Default)]
pub struct LDC_W {
    index: usize
}

impl Instruction for LDC_W {
    fn fetch_operands(&mut self, reader: &mut crate::instructions::base::BytecodeReader) {
        self.index = reader.read_u16() as usize;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        _ldc(frame, self.index)
    }
}

fn _ldc(frame: Rc<RefCell<Frame>>, index: usize) {
    let stack = frame.borrow().get_operand_stack();
    let method = frame.borrow().get_method();
    let cp = method.get_class().get_constant_pool().unwrap();
    let c = cp.get_constant(index);
    match c.unwrap() {
        Constant::Int(val) => stack.borrow_mut().push_int(val),
        Constant::Float(val) => stack.borrow_mut().push_float(val),
        Constant::String(val) => {
            let interned_str = string_pool::j_string(&mut method.get_class().get_class_loader().unwrap().lock().unwrap(), &val);
            stack.borrow_mut().push_ref(Some(interned_str));
        },
        Constant::ClassRef(val) => {
            let class = val.lock().unwrap().resolved_class();
            let class_obj = class.get_j_class().unwrap();
            stack.borrow_mut().push_ref(Some(class_obj));
        }
        _ => panic!("todo: ldc!")
    }
}

// ldc2_w指令用于加载long和double常量。
#[derive(Debug, Default)]
pub struct LDC2_W {
    index: usize
}

impl Instruction for LDC2_W {
    fn fetch_operands(&mut self, reader: &mut crate::instructions::base::BytecodeReader) {
        self.index = reader.read_u16() as usize;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let cp = frame.borrow().get_method().get_class().get_constant_pool().unwrap();
        let c = cp.get_constant(self.index);

        match c.unwrap() {
            Constant::Long(val) => stack.borrow_mut().push_long(val),
            Constant::Double(val) => stack.borrow_mut().push_double(val),
            _ => panic!("java.lang.ClassFormatError")
        }
    }
}